package cn.example.gate.plugins.netty;

import cn.example.gate.netty.codec.NettyCodec;
import cn.example.gate.netty.handler.NettyHandler;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.artifact.core.lang.IPlugin;

import java.util.concurrent.TimeUnit;

public class NettyPlugin implements IPlugin {

	static final Log log = LogFactory.get(NettyPlugin.class);

	private int prot;

	private EventLoopGroup bossGroup = null;

	private EventLoopGroup workerGroup = null;

	private static final int TIMEOUT = 60000;

	public NettyPlugin(int prot) {
		super();
		this.prot = prot;
	}

	@Override
	public boolean start() {
		try {
			bossGroup = new NioEventLoopGroup(1);
			workerGroup = new NioEventLoopGroup();
			ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100) // BACKLOG用于构造服务端套接字ServerSocket对象，标识当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度。如果未设置或所设置的值小于1，Java将使用默认值50。
					.option(ChannelOption.TCP_NODELAY, true) // 在TCP/IP协议中，无论发送多少数据，总是要在数据前面加上协议头，同时，对方接收到数据，也需要发送ACK表示确认。为了尽可能的利用网络带宽，TCP总是希望尽可能的发送足够大的数据。这里就涉及到一个名为Nagle的算法，该算法的目的就是为了尽可能发送大块数据，避免网络中充斥着许多小数据块。TCP_NODELAY就是用于启用或关于Nagle算法。如果要求高实时性，有数据发送时就马上发送，就将该选项设置为true关闭Nagle算法；如果要减少发送次数减少网络交互，就设置为false等累积一定大小后再发送。默认为false。
					.option(ChannelOption.SO_REUSEADDR, true) // 端口释放后立即就可以被再次使用
					.option(ChannelOption.AUTO_READ, true)
					// .option(ChannelOption.ALLOCATOR,
					// PooledByteBufAllocator.DEFAULT)
					// .childOption(ChannelOption.ALLOCATOR,
					// PooledByteBufAllocator.DEFAULT)
					.handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {
						@Override
						public void initChannel(SocketChannel ch) throws Exception {
							ChannelPipeline p = ch.pipeline();
							p.addLast("codec", new NettyCodec());

							p.addLast(new IdleStateHandler(0, 0, TIMEOUT, TimeUnit.MILLISECONDS));
							// p.addLast(eventExecutorGroup,new NettyHandler());
							// p.addLast(new HeartbeatHandler());
							// p.addLast(new InterceptHandler());
							p.addLast(new NettyHandler());
						}
					});
			b.bind(prot).sync();
		} catch (Exception e) {
			log.error(e);
			return false;
		}
		return true;
	}

	public boolean stop() {
		try {
			bossGroup.shutdownGracefully().sync();
			workerGroup.shutdownGracefully().sync();
			log.info("Netty Server Stop Success!");
		} catch (InterruptedException e) {
			log.error(e);
		}
		return true;
	}

}
